#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/provider.h>

void handleErrors() {
    ERR_print_errors_fp(stderr);
    abort();
}

int main(int argc, char *argv[]) {
    EVP_PKEY *pkey = NULL;
    EVP_PKEY_CTX *ctx = NULL;

    // 检查命令行参数
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <private_key_file.pem> <public_key_file.pem>\n", argv[0]);
        return EXIT_FAILURE;
    }

    // 初始化 OpenSSL
    if (OPENSSL_init_crypto(0, NULL) == 0) {
        fprintf(stderr, "Failed to initialize OpenSSL\n");
        return EXIT_FAILURE;
    }
    ERR_load_crypto_strings();

    // 创建上下文
    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL);
    if (!ctx) {
        fprintf(stderr, "Failed to create EVP_PKEY_CTX\n");
        handleErrors();
    }

    // 初始化密钥生成
    if (EVP_PKEY_keygen_init(ctx) <= 0) {
        fprintf(stderr, "Failed to initialize key generation\n");
        handleErrors();
    }

    // 生成密钥
    if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
        fprintf(stderr, "Failed to generate SM2 key\n");
        handleErrors();
    }

    // 输出生成的私钥到指定文件
    FILE *priv_key_file = fopen(argv[1], "w");
    if (!priv_key_file) {
        fprintf(stderr, "Failed to open file for writing private key\n");
        handleErrors();
    }

    if (PEM_write_PrivateKey(priv_key_file, pkey, NULL, NULL, 0, NULL, NULL) != 1) {
        fprintf(stderr, "Failed to write private key to file\n");
        handleErrors();
    }
    fclose(priv_key_file);
    printf("SM2 private key has been written to %s\n", argv[1]);

    // 输出生成的公钥到指定文件
    FILE *pub_key_file = fopen(argv[2], "w");
    if (!pub_key_file) {
        fprintf(stderr, "Failed to open file for writing public key\n");
        handleErrors();
    }

    if (PEM_write_PUBKEY(pub_key_file, pkey) != 1) {
        fprintf(stderr, "Failed to write public key to file\n");
        handleErrors();
    }
    fclose(pub_key_file);
    printf("SM2 public key has been written to %s\n", argv[2]);

    // 释放资源
    EVP_PKEY_free(pkey);
    EVP_PKEY_CTX_free(ctx);
    ERR_free_strings();
    return EXIT_SUCCESS;
}
